package com.examsystem.controller;



import com.alibaba.fastjson.JSON;
import com.examsystem.Const.ConstMsg;
import com.examsystem.pojo.vo.Result;
import com.examsystem.util.AutoHandler;
import com.examsystem.util.JwtUtil;
import com.examsystem.util.RedisUtil;
import com.examsystem.pojo.PaperClass;
import com.examsystem.service.PaperClassService;
import com.examsystem.service.UserPaperService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author fire'ge
 */
@Controller
@EnableScheduling
@RequestMapping("/autoSubmit")

public class AutoSubmitController {
    @Resource
   private UserPaperService userPaperservice;
    @Resource
   private PaperClassService paperClassService;
    @Resource
    private RedisUtil redisUtil;
    Map<String,ScheduledFuture<?>> scheduledFutureMap =new HashMap<>();

    /**
     * 创建一个新的自动交卷的线程，让自动交卷开始
     * @param request 读取request中的请求头中的token，解析成userId
     * @param paperId 这个是自动交卷所需的paperId
     * @return 返回创建自动交卷成功后的结果
     */
    @ResponseBody
    @RequestMapping("/autoSubmit/{paperId}")
    @PreAuthorize("hasAuthority('autoSubmit:newAuto')")
    public String checkSubmitPaper(HttpServletRequest request,@PathVariable int paperId){
        //获取用户的token，从而获取userid

        String token = request.getHeader(ConstMsg.TOKEN_PARAM);
        int jwtUserId = JwtUtil.getJWTUserId(token);

        //检查该用户的试卷在redis中是否已经有了数据（考试剩余时间），如果存在就直接开启任务
        if (redisUtil.get(ConstMsg.PAPER_PARAM + paperId + ConstMsg.USER_PARAM + jwtUserId)==null){
            PaperClass paperClass = paperClassService.queryPaperClassByUserIdAndPaperId(jwtUserId, paperId);
            int pcExamTime = paperClass.getPcExamTime()*60;
            redisUtil.set("paper:"+paperId+"user:"+jwtUserId,pcExamTime+"");
        }
        //开启定时任务

        getSubmitPaper(jwtUserId,paperId);
        return JSON.toJSONString(Result.succ("创建自动交卷成功"));
    }

    /**
     * 是用来开启线程的方法，创建好了一个线程池来实行定时任务
     * @param userId 用户的id，主要是用来查询用户的状态和从redis中取出缓存的考试时间减秒
     * @param paperId  paperId,试卷的id从redis中取出缓存的考试时间减秒
     */
    public void getSubmitPaper(int userId,int paperId){
        //创建线程池
        ScheduledExecutorService service = new ScheduledThreadPoolExecutor(100);
        //开启任务，每秒执行一次
        ScheduledFuture<?> scheduledFuture = service.scheduleAtFixedRate(new DecrExamTime(userId, paperId), 0, 1000, TimeUnit.MILLISECONDS);
        //将定时任务放入到定时任务池里面
        scheduledFutureMap.put(ConstMsg.PAPER_PARAM+paperId+ConstMsg.USER_PARAM+userId, scheduledFuture);
    }

    /**
     * 定时任务类，用来将储存再redis中的时间检测和减少
     */
    class DecrExamTime implements Runnable {
        //将用户id和试卷的id传入，用来获取到自己管辖的redis数据（该用户的这张试卷的考试剩余时间）
        private final int userId;
        private final int paperId;

        public DecrExamTime(int userId, int paperId) {
            this.userId = userId;
            this.paperId = paperId;
        }

        @Override
        public void run() {
            //获取该用户的登录状态，不在在线状态，则取消定时任务
            if (redisUtil.get(ConstMsg.LOGIN_USER_PARAM + userId) == null) {

                ScheduledFuture<?> scheduledFuture = scheduledFutureMap.get(ConstMsg.PAPER_PARAM + paperId + ConstMsg.USER_PARAM + userId);
                scheduledFuture.cancel(true);
                return;
            }
            String pcTimeStr = (String) redisUtil.get(ConstMsg.PAPER_PARAM + paperId + ConstMsg.USER_PARAM + userId);
            //将时间减一
            if (pcTimeStr != null) {
                int pcTime = Integer.parseInt(pcTimeStr);
                pcTime--;
                //如果考试剩余时间已到了，则修改试卷的交卷状态，取消定时任务
                if (pcTime <= 0) {

                    redisUtil.del(ConstMsg.PAPER_PARAM + paperId + ConstMsg.USER_PARAM + userId);
                    userPaperservice.updateUserPaper(userId);
                    ScheduledFuture<?> scheduledFuture = scheduledFutureMap.get("paper:" + paperId + ConstMsg.USER_PARAM + userId);
                    scheduledFuture.cancel(true);
                    return;
                }
                //将新数据存入到redis中
               redisUtil.set(ConstMsg.PAPER_PARAM + paperId + ConstMsg.USER_PARAM + userId, pcTime + "");
            } else {
                ScheduledFuture<?> scheduledFuture = scheduledFutureMap.get(ConstMsg.PAPER_PARAM + paperId + ConstMsg.USER_PARAM + userId);
                scheduledFuture.cancel(true);
            }
        }
    }



    /*
    教师端
     */

    @Autowired
    private AutoHandler autoHandler;

    /**
     * 自动交卷
     * @param paperId 试卷id
     * @param studentId  学生id
     * @param classId  班级id
     * @return  result结果集对象
     */
    @RequestMapping("/autoHandler/{paperId}/{studentId}/{classId}")
    @ResponseBody
    public Result autoHandler(@PathVariable Integer paperId,@PathVariable Integer studentId,@PathVariable Integer classId){
        return autoHandler.autoHandler(paperId, studentId, classId);
    }
}
